package com.dc.aimc.auth.config;

import com.dc.aimc.auth.security.AimcClientDetailsService;
import com.dc.aimc.auth.security.AimcUserDetailsService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.sql.DataSource;

/**
 * SpringSecurity OAuth2.0 认证服务器配置
 */
@Log4j2
@Configuration
@EnableAuthorizationServer
public class AimcAuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AimcUserDetailsService aimcUserDetailsService;


    @Autowired
    private AimcClientDetailsService aimcClientDetailsService;

    @Autowired
    private AuthorizationCodeServices jdbcAuthorizationCodeServices;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;


    /**
     * 授权码服务
     * @param dataSource
     * @return
     */
    @Bean
    public AuthorizationCodeServices jdbcAuthorizationCodeServices(DataSource dataSource) {
        // 设置授权码模式的授权码如何存取
        return new JdbcAuthorizationCodeServices(dataSource);
    }


    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security
                // 公开oauth/token_key
                .tokenKeyAccess("permitAll()")
                // 公开oauth/check_token
                .checkTokenAccess("permitAll()")
                // 允许表单认证/oauth/token  使用client_id和client_secret获取token
                .allowFormAuthenticationForClients();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 客户端模式(client_credentials)下从数据库获取客户端详细信息
        clients.withClientDetails(aimcClientDetailsService);
    }


    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        // 密码模式(password)下配置认证管理器 AuthenticationManager
        endpoints.authenticationManager(authenticationManager).userDetailsService(aimcUserDetailsService);
        // 授权码模式(authentication code)
        endpoints.authorizationCodeServices(jdbcAuthorizationCodeServices);
        // 设置 AccessToken的存储介质tokenStore
        endpoints.tokenStore(tokenStore).accessTokenConverter(jwtAccessTokenConverter);
        // 对GET, POST, PUT, DELETE请求进行token认证
        endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE);
    }
}
